﻿// owner 蒋家伟

#pragma once
#include "DataSchema_home.h"
#include "DBSchemaObject.h"

namespace jsdk
{
    class UniqueId;
    // 类别描述 : 类别的字段描述符号，通过变量名称，类型Id与地址偏移描述一个类的成员变量
    class DATASCHEMA_EXPORT IClassFieldDescriptor
    {
    public:
        virtual ~IClassFieldDescriptor() {}

        /// \ brief 传递class的指针与接收值获取类成员的变量值
        /// \ note : 拷贝
        /// \ in   pClass class类别对象的指针
        /// \ out  value  接收值的对象
        template<typename ValueType>
        const ValueType* get() const
        {
            if (!this->isValidType<ValueType>())
            {
                throw std::bad_cast();
                return nullptr;
            }
            return (const ValueType*)(this->getFiledAddress());
        }

        /// \ brief 根据传入的模版类型判断当前get或者set等传入的类别是否有效
        /// \ return 如果传入失败则会抛出异常
        template<typename ValueType> 
        bool isValidType() const noexcept {
            return typeid(ValueType).hash_code() == this->getTypeHashCode();
        }

        /// \ brief 将传入的值设置给class的字段
        /// \ in   pClass class类别对象的指针
        /// \ int  value  输入的值
        template<typename ValueType>
        bool set(const ValueType& value)
        {
            if (!this->isValidType<ValueType>())
            {
                throw std::bad_cast();
                return false;
            }
            if (void* pFiledAddress = this->getFiledAddress())
            {
                (*((ValueType*)pFiledAddress)) = value;
                return true;
            }
            return false;
        }

        /// \ brief 右值版本，减少数据的拷贝。但是目标对象必须实现swap方法
        template<typename ValueType, typename = std::enable_if_t<TemplateCommonUtils::has_swap_fun<TemplateCommonUtils::Decay_t<ValueType>>::value>>
        bool set(ValueType&& value)
        {
            using decay_type = TemplateCommonUtils::Decay_t<ValueType>;
            if (!this->isValidType<decay_type>())
            {
                throw std::bad_cast();
                return false;
            }
            if (void* pFiledAddress = this->getFiledAddress())
            {
                (*((decay_type*)pFiledAddress)).swap(value);
                return true;
            }
            return false;
        }

        /// \ breif 特化 DBSchemaObject 存储类型为DBSchemaObject版本
        /// \ in opSourceSchemaObject 原Schema对象
        bool set(jsdk::OwnerPtr<DBSchemaObject> opSourceSchemaObject)
        {
            jsdk::OwnerPtr<DBSchemaObject> opNeWDBSchemaObject = nullptr;
            if (opSourceSchemaObject)
            {
                opNeWDBSchemaObject.swap(this->getCastDBSchemaObject(transformOwnerShip(opSourceSchemaObject)));
                if (opNeWDBSchemaObject == nullptr)
                {
                    throw std::bad_cast();
                    return false;
                }
            }
            if (void* pFiledAddress = this->getFiledAddress())
            {
                (*((jsdk::OwnerPtr<DBSchemaObject>*) pFiledAddress)).swap(opNeWDBSchemaObject);
                return true;
            }
            return false;
        }

    public:
        /// \ brief 获取变量的名称
        /// \ return 变量的名称
        virtual const std::wstring& getVariableName() const noexcept = 0;

        /// \ brief 获取类别Hash值
        virtual const std::size_t& getTypeHashCode() const noexcept = 0;

        /// \ brief 获取类别名称
        /// \ return 类别名称
        virtual const std::wstring& getTypeName() const noexcept = 0;

        /// \ breif 获取序列化的object对象
        /// \ in/out     序列化所在的文档，用于分配内存。
        /// \ out object 返回被序列化完成的object对象
        /// \ return true 表示object 对象是否有效， false表示序列化失败
        virtual bool serialize(JsonDocument& jsonDoc, JsonObject& jsonObject) const noexcept = 0;

        /// \ brief 反序列化对象
        /// \ in object 反流的json对象
        /// \ return ture 表示反流成功，false表示反流失败
        virtual bool unserialize(const JsonObject& jsonObject) noexcept = 0;

    private:
        friend class FieldReflectManager;

        /// \ brief 设置类别实例的地址
        /// \ in pClassAddress 类别实例的地址
        virtual void setClassAddress(void* pClassAddress) noexcept = 0;

        /// \ brief 获取当前描述符对应的字段的地址
        virtual const void* getFiledAddress() const noexcept = 0;
        virtual void* getFiledAddress() noexcept = 0;

        /// \ brief 根据原始类型进行cast，主要用于修改指针的偏移
        /// \ in opSourceDBSchemaObject 原始db层数据对象
        /// \ return jsdk::OwnerPtr<DBSchemaObject> 指针已经正确偏移的对象
        virtual jsdk::OwnerPtr<DBSchemaObject> getCastDBSchemaObject(jsdk::OwnerPtr<DBSchemaObject> opSourceDBSchemaObject) const noexcept = 0;

        /// \ brief 设置所属类别的uid与名称
        virtual void setOwnerClassNameAndUid(const std::wstring& className, const jsdk::UniqueId& uid) noexcept = 0;
    };
}
